/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.editor.java;
import java.awt.Dialog;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.ResourceBundle;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import javax.swing.ImageIcon;
import javax.swing.ListCellRenderer;
import org.netbeans.editor.ext.JCClass;
import org.netbeans.editor.ext.JCType;
import org.netbeans.editor.ext.JCConstructor;
import org.netbeans.editor.ext.JCMethod;
import org.netbeans.editor.ext.JCField;
import org.netbeans.editor.ext.JCParameter;
import org.netbeans.editor.ext.JCompletion;
import org.netbeans.editor.ext.JCFinder;
import org.netbeans.editor.ext.JCCellRenderer;
import org.netbeans.editor.ext.JCQuery;
import org.openide.src.ClassElement;
import org.openide.src.ConstructorElement;
import org.openide.src.MethodElement;
import org.openide.src.FieldElement;
import org.openide.src.Identifier;
import org.openide.src.SourceElement;
import org.openide.src.Type;
import org.openide.src.MethodParameter;
import org.openide.src.nodes.ElementNode;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataFolder;
import org.openide.nodes.Node;
import org.openide.cookies.SourceCookie;
import org.openide.filesystems.FileObject;
import org.openide.TopManager;
import org.openide.DialogDescriptor;
import org.openide.util.NbBundle;
import org.openide.util.HelpCtx;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.filesystems.FileSystem;
import org.openide.util.enum.QueueEnumeration;
/**
* Extended Java Completion support
*
* @author Miloslav Metelka
* @version 1.00
*/
public class JCExtension {
public static boolean equals(JCClass cls1, ClassElement cls2) {
return cls1.getFullName().equals(cls2.getName().getFullName());
}
public static boolean equals(JCType typ1, Type typ2) {
// Get array depth of the type
int arrayDepth = 0;
while(typ2.isArray()) {
arrayDepth++;
typ2 = typ2.getElementType();
}
String fn = typ2.isPrimitive() ? typ2.getFullString()
: typ2.getClassName().getFullName();
return (typ1.getArrayDepth() == arrayDepth)
&& typ1.getClazz().getFullName().equals(fn);
}
public static boolean equals(JCField fld1, FieldElement fld2) {
return fld1.getName().equals(fld2.getName().getFullName())
&& equals(fld1.getType(), fld2.getType());
}
public static boolean equals(JCConstructor ctr1, ConstructorElement ctr2) {
JCParameter[] parms1 = ctr1.getParameters();
MethodParameter[] parms2 = ctr2.getParameters();
if (parms2 == null || parms1.length != parms2.length) {
return false;
}
for (int i = parms1.length - 1; i >= 0; i--) {
if (!equals(parms1[i].getType(), parms2[i].getType())) {
return false;
}
}
return true;
}
public static boolean equals(JCMethod mtd1, MethodElement mtd2) {
return mtd1.getName().equals(mtd2.getName().getFullName())
&& equals((JCConstructor)mtd1, (ConstructorElement)mtd2);
}
public static FieldElement findFieldElement(JCField fld, ClassElement ce) {
FieldElement[] fes = ce.getFields();
if (fes != null) {
for (int i = 0; i < fes.length; i++) {
if (equals(fld, fes[i])) {
return fes[i];
}
}
}
return null;
}
public static ConstructorElement findConstructorElement(JCConstructor ctr, ClassElement ce) {
ConstructorElement[] ces = ce.getConstructors();
if (ces != null) {
for (int i = 0; i < ces.length; i++) {
if (equals(ctr, ces[i])) {
return ces[i];
}
}
}
return null;
}
public static MethodElement findMethodElement(JCMethod mtd, ClassElement ce) {
MethodElement[] mes = ce.getMethods();
if (mes != null) {
for (int i = 0; i < mes.length; i++) {
if (equals(mtd, mes[i])) {
return mes[i];
}
}
}
return null;
}
/** Get or create the simple class from identifier.
* @param i identifier holding the class information
* @param lookupCache cache holding the [name, simple-class] pairs for already found classes
* @param preferFinder whether the package name finding should be first tried
* through the finder or through the ClassElement.forName()
*/
static JCClass getIdentifierClass(Identifier i, Map lookupCache, boolean preferFinder) {
String fn = i.getFullName(); // Get identifier's full name
// First try the lookupCache
JCClass cls = (JCClass)lookupCache.get(fn);
if (cls != null) {
return cls;
}
// Try finder if it's preferred
if (preferFinder) {
JCFinder finder = JCompletion.getFinder();
if (finder != null) {
cls = finder.getExactClass(fn); // try to find through the current finder
if (cls != null) {
cls = JCompletion.getSimpleClass(cls); // be sure to have simple class
lookupCache.put(fn, cls);
return cls;
}
}
}
int pkgLen = -1; // will try to find the correct package length
// Try to get class element based on fullname
ClassElement ce;
try {
ce = ClassElement.forName(fn);
} catch (Throwable t) { // Parser sometimes sensitive to forName call !!!
System.err.println("Error occurred during name resolving"); // NOI18N
t.printStackTrace();
return JCompletion.INVALID_CLASS;
}
// Try to split the fullname by finding the package of the source element
if (ce != null) {
SourceElement se = ce.getSource();
if (se != null) {
Identifier pi = null;
pi = se.getPackage();
if (pi != null) {
String pkgName = pi.getFullName();
if (fn.startsWith(pkgName)) { // validity check
pkgLen = pkgName.length();
}
}
}
}
// If failed try to resolve through the current finder
if (pkgLen < 0) {
JCFinder finder = JCompletion.getFinder();
if (finder != null) {
if (!preferFinder) { // already tried for preferFinder == true
cls = finder.getExactClass(fn);
}
if (cls == null) { // not exact fullname, try by name only
List clsList = finder.findClasses(null, fn, true);
if (clsList != null && clsList.size() == 1) { // only when exactly one match
cls = (JCClass)clsList.get(0);
}
}
if (cls != null) {
cls = JCompletion.getSimpleClass(cls); // be sure to have simple class
lookupCache.put(fn, cls);
return cls;
}
}
}
// Last instance - guess the package from the full name by heuristic
// Go from the last name to the previous if it has a first capital letter
if (pkgLen < 0) {
pkgLen = Math.max(fn.lastIndexOf('.'), 0);
String pkgName = fn.substring(0, pkgLen);
int lastDotInd = pkgName.lastIndexOf('.');
if (lastDotInd < fn.length() - 1) { // '.' would be last in fn
while (lastDotInd >= 0 && Character.isUpperCase(fn.charAt(lastDotInd + 1))) {
pkgName = pkgName.substring(0, lastDotInd);
pkgLen = lastDotInd;
lastDotInd = pkgName.lastIndexOf('.');
}
}
}
// Get the class
cls = JCompletion.getSimpleClass(fn, pkgLen);
lookupCache.put(fn, cls);
return cls;
}
/*
DEBUG to getIdentifierClass() that test if the class is reachable
if (pkgName != null && clsName != null) {
try { // !!! Try to create the class without init
Class.forName(pkgName + '.' + clsName.replace('.', '$'), false, JCExtension.class.getClassLoader());
} catch (ClassNotFoundException e) {
System.out.println("Class not found: '" + pkgName + '.' + clsName + "', fn='" + fn + "'"); // NOI18N
}
}
*/
static JCType getType(Type t, Map lookupCache, boolean preferFinder) {
// Get array depth of the type
int arrayDepth = 0;
while(t.isArray()) {
arrayDepth++;
t = t.getElementType();
}
JCClass c;
if (t.isPrimitive()) {
c = JCompletion.getPrimitiveClass(t.getFullString());
} else {
c = getIdentifierClass(t.getClassName(), lookupCache, preferFinder);
}
return JCompletion.getType(c, arrayDepth);
}
/** Create the new instance of JCClass based on the information provided by the class element.
*/
static JCClass parseClassElement(ClassElement ce, int classLevel, int fieldLevel,
int methodLevel, Map lookupCache, boolean preferFinder) {
JCClass sc = getIdentifierClass(ce.getName(), lookupCache, preferFinder);
if (sc.equals(JCompletion.INVALID_CLASS)) { // error occurred
return null;
}
return new NbJCClass(sc.getName(), sc.getPackageName(),
ce.isInterface(), ce.getModifiers(),
ce, classLevel, fieldLevel, methodLevel, lookupCache, preferFinder);
}
static class NbJCClass extends JCompletion.AbstractClass {
public NbJCClass(String name, String packageName,
boolean iface, int modifiers,
ClassElement ce, int classLevel, int fieldLevel,
int methodLevel, Map lookupCache, boolean preferFinder) {
super(name, packageName, iface, modifiers);
body = new Body(); // init directly
ArrayList lst = new ArrayList();
Identifier sc = ce.getSuperclass();
body.superClass = (sc != null) ? getIdentifierClass(sc, lookupCache, preferFinder)
: (iface ? JCompletion.INVALID_CLASS : JCompletion.OBJECT_CLASS);
// Get interfaces
Identifier[] cei = ce.getInterfaces();
body.interfaces = JCompletion.EMPTY_CLASSES;
if (cei != null) {
for (int i = 0; i < cei.length; i++) {
if (cei[i] != null) {
// if (getLevel(cei[i].getModifiers()) >= classLevel) { NOT SPECIF IED IN SOURCE
lst.add(getIdentifierClass(cei[i], lookupCache, preferFinder));
// }
}
}
body.interfaces = new JCClass[lst.size()];
lst.toArray(body.interfaces);
lst.clear();
}
// Get fields
FieldElement[] cef = ce.getFields();
body.fields = JCompletion.EMPTY_FIELDS;
if (cef != null) {
for (int i = 0; i < cef.length; i++) {
if (cef[i] != null) {
if (JCompletion.getLevel(cef[i].getModifiers()) >= fieldLevel) {
lst.add(new JCompletion.BaseField(this, cef[i].getName().getName(),
getType(cef[i].getType(), lookupCache, preferFinder),
cef[i].getModifiers())
);
}
}
}
body.fields = new JCField[lst.size()];
lst.toArray(body.fields);
lst.clear();
}
// Get constructors
ConstructorElement[] cec = ce.getConstructors();
body.constructors = JCompletion.EMPTY_CONSTRUCTORS;
if (cec != null) {
for (int i = 0; i < cec.length; i++) {
if (cec[i] != null) {
if (JCompletion.getLevel(cec[i].getModifiers()) >= methodLevel) {
// get constructor parameters
JCParameter[] parameters = JCompletion.EMPTY_PARAMETERS;
MethodParameter[] cep = cec[i].getParameters();
if (cep != null) {
parameters = new JCParameter[cep.length];
for (int j = 0; j < cep.length; j++) {
int type;
parameters[j] = new JCompletion.BaseParameter(
cep[j].getName(),
getType(cep[j].getType(), lookupCache, preferFinder)
);
}
}
// get thrown exceptions - don't restrict to classes level
JCClass[] exceptions = JCompletion.EMPTY_CLASSES;
Identifier[] cee = cec[i].getExceptions();
exceptions = new JCClass[cee.length];
for (int j = 0; j < cee.length; j++) {
exceptions[j] = getIdentifierClass(cee[j], lookupCache, preferFinder);
}
lst.add(new JCompletion.BaseConstructor(this, cec[i].getModifiers(),
parameters, exceptions));
}
}
}
body.constructors = new JCConstructor[lst.size()];
lst.toArray(body.constructors);
lst.clear();
}
// Get methods
MethodElement[] cem = ce.getMethods();
body.methods = JCompletion.EMPTY_METHODS;
if (cem != null) {
for (int i = 0; i < cem.length; i++) {
if (cem[i] != null) {
int mods = cem[i].getModifiers();
if (iface) { // all interface methods are public
mods |= Modifier.PUBLIC;
}
if (JCompletion.getLevel(mods) >= methodLevel) {
// get constructor parameters
JCParameter[] parameters = JCompletion.EMPTY_PARAMETERS;
MethodParameter[] cep = cem[i].getParameters();
if (cep != null) {
parameters = new JCParameter[cep.length];
for (int j = 0; j < cep.length; j++) {
int type;
parameters[j] = new JCompletion.BaseParameter(
cep[j].getName(),
getType(cep[j].getType(), lookupCache, preferFinder)
);
}
}
// get thrown exceptions - don't restrict to classes level
JCClass[] exceptions = JCompletion.EMPTY_CLASSES;
Identifier[] cee = cem[i].getExceptions();
exceptions = new JCClass[cee.length];
for (int j = 0; j < cee.length; j++) {
exceptions[j] = getIdentifierClass(cee[j], lookupCache, preferFinder);
}
lst.add(new JCompletion.BaseMethod(this,
cem[i].getName().getName(), mods,
getType(cem[i].getReturn(), lookupCache, preferFinder),
parameters, exceptions));
}
}
}
}
body.methods = new JCMethod[lst.size()];
lst.toArray(body.methods);
lst.clear();
}
protected void init() {
// already done
}
}
}
/*
* Log
* 16 Gandalf 1.15 1/13/00 Miloslav Metelka Localization
* 15 Gandalf 1.14 1/11/00 Miloslav Metelka
* 14 Gandalf 1.13 12/28/99 Miloslav Metelka
* 13 Gandalf 1.12 11/15/99 Miloslav Metelka getIdentifierClass()
* 12 Gandalf 1.11 11/14/99 Miloslav Metelka
* 11 Gandalf 1.10 11/11/99 Miloslav Metelka
* 10 Gandalf 1.9 11/8/99 Miloslav Metelka
* 9 Gandalf 1.8 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 8 Gandalf 1.7 9/30/99 Miloslav Metelka
* 7 Gandalf 1.6 9/15/99 Miloslav Metelka
* 6 Gandalf 1.5 8/27/99 Miloslav Metelka
* 5 Gandalf 1.4 8/18/99 Miloslav Metelka
* 4 Gandalf 1.3 8/18/99 Miloslav Metelka
* 3 Gandalf 1.2 7/21/99 Miloslav Metelka
* 2 Gandalf 1.1 7/21/99 Miloslav Metelka
* 1 Gandalf 1.0 7/20/99 Miloslav Metelka
* $
*/